package com.x.provider.general.service.cms;

import com.x.core.utils.CompareUtils;
import com.x.provider.api.common.enums.ItemTypeEnum;
import com.x.provider.api.general.model.dto.cms.ItemStatListReqDTO;
import com.x.provider.api.general.model.dto.cms.StarSaveReqDTO;
import com.x.provider.api.statistic.enums.MetricEnum;
import com.x.provider.api.statistic.enums.PeriodEnum;
import com.x.provider.api.statistic.model.dto.MetricValueIncReqDTO;
import com.x.provider.api.statistic.model.dto.MetricValuesIncReqDTO;
import com.x.provider.api.statistic.model.dto.MetricValueListReqDTO;
import com.x.provider.api.statistic.model.dto.MetricValueBatchListReqDTO;
import com.x.provider.api.statistic.model.dto.MetricValueDTO;
import com.x.provider.api.statistic.service.StatisticTotalRpcService;
import com.x.provider.general.model.domain.cms.Comment;
import com.x.provider.general.model.domain.cms.ItemStatistic;
import com.x.provider.general.model.domain.cms.Star;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ItemStatServiceImpl implements ItemStatService {

    private final StatisticTotalRpcService statisticTotalRpcService;

    public ItemStatServiceImpl(StatisticTotalRpcService statisticTotalRpcService){
        this.statisticTotalRpcService = statisticTotalRpcService;
    }

    @Override
    public void onCommentInsert(Comment comment) {
        ItemStatistic commentStat = ItemStatistic.builder().itemId(comment.getItemId()).itemType(comment.getItemType()).commentCount(1L).build();
        incItemStat(commentStat);
    }

    @Override
    public void onStar(StarSaveReqDTO star) {
        if (star.getItemType().equals(ItemTypeEnum.COMMENT.getValue())){
            return;
        }
        ItemStatistic commentStat = ItemStatistic.builder().itemId(star.getItemId()).itemType(star.getItemType()).starCount(star.getStar() ? 1L : -1).customerId(star.getStarCustomerId()).build();
        incItemStat(commentStat);
    }

    @Override
    public Map<Long, ItemStatistic> listItemStatMap(ItemStatListReqDTO itemStatListReqDTO) {
        List<MetricValueListReqDTO> conditions = new ArrayList<>();
        List<String> itemIdList = itemStatListReqDTO.getIdList().stream().map(String::valueOf).collect(Collectors.toList());
        if (itemStatListReqDTO.getMetricList().contains(MetricEnum.COMMENT_COUNT.getValue())) {
            conditions.add(MetricValueListReqDTO.builder()
                    .itemIdList(itemIdList)
                    .itemType(itemStatListReqDTO.getItemType())
                    .metric(MetricEnum.COMMENT_COUNT.getValue())
                    .period(PeriodEnum.ALL.getValue())
                    .build());
        }
        if (itemStatListReqDTO.getMetricList().contains(MetricEnum.STAR_COUNT.getValue())) {
            conditions.add(MetricValueListReqDTO.builder()
                    .itemIdList(itemIdList)
                    .itemType(itemStatListReqDTO.getItemType())
                    .metric(MetricEnum.STAR_COUNT.getValue())
                    .period(PeriodEnum.ALL.getValue())
                    .build());
        }
        if (itemStatListReqDTO.getMetricList().contains(MetricEnum.MY_STAR_COUNT.getValue())){
            conditions.add(MetricValueListReqDTO.builder()
                    .itemIdList(itemIdList)
                    .itemType(ItemTypeEnum.CUSTOMER.getValue())
                    .metric(MetricEnum.MY_STAR_COUNT.getValue())
                    .fromItemType(itemStatListReqDTO.getItemType())
                    .period(PeriodEnum.ALL.getValue())
                    .build());
        }
        MetricValueBatchListReqDTO listMetricValueBatchAO = new MetricValueBatchListReqDTO();
        listMetricValueBatchAO.setConditions(conditions);
        List<MetricValueDTO> metricValues = statisticTotalRpcService.listStatisticTotalBatch(listMetricValueBatchAO).getData();
        return prepare(metricValues);
    }

    public void incItemStat(ItemStatistic itemStat){
        List<MetricValueIncReqDTO> incMetricValueValuesAO = new ArrayList<>();
        if (itemStat.getCommentCount() != null){
            incMetricValueValuesAO.add(MetricValueIncReqDTO.builder()
                    .itemId(itemStat.getItemId().toString())
                    .itemType(itemStat.getItemType())
                    .metric(MetricEnum.COMMENT_COUNT.getValue())
                    .period(PeriodEnum.ALL.getValue())
                    .longValue(itemStat.getCommentCount()).build());
        }
        if (itemStat.getStarCount() != null){
            incMetricValueValuesAO.add(MetricValueIncReqDTO.builder()
                    .itemId(itemStat.getItemId().toString())
                    .itemType(itemStat.getItemType())
                    .metric(MetricEnum.STAR_COUNT.getValue())
                    .period(PeriodEnum.ALL.getValue())
                    .longValue(itemStat.getStarCount()).build());

            incMetricValueValuesAO.add(MetricValueIncReqDTO.builder()
                    .itemId(itemStat.getCustomerId().toString())
                    .itemType(ItemTypeEnum.CUSTOMER.getValue())
                    .metric(MetricEnum.MY_STAR_COUNT.getValue())
                    .fromItemType(itemStat.getItemType())
                    .period(PeriodEnum.ALL.getValue())
                    .longValue(itemStat.getStarCount()).build());
        }
        if (incMetricValueValuesAO.isEmpty()){
            return;
        }
        statisticTotalRpcService.incStatisticTotals(MetricValuesIncReqDTO.builder().incMetricValues(incMetricValueValuesAO).build());
    }

    private Map<Long, ItemStatistic> prepare(List<MetricValueDTO> metricValues){
        if (metricValues.isEmpty()){
            return new HashMap<>();
        }
        Map<Long, ItemStatistic> result = new HashMap<>(32);
        metricValues.stream().forEach(item -> {
            ItemStatistic itemStatistic = result.getOrDefault(Long.valueOf(item.getItemId()), ItemStatistic.builder().itemId(Long.valueOf(item.getItemId()))
                    .itemType(item.getItemType()).build());
            if (Objects.equals(item.getMetric(), MetricEnum.STAR_COUNT.getValue())){
                itemStatistic.setStarCount(item.getLongValue());
            }
            if (Objects.equals(item.getItemType(), ItemTypeEnum.COMMENT.getValue()) && Objects.equals(item.getMetric(), MetricEnum.COMMENT_COUNT.getValue())){
                itemStatistic.setCommentCount(item.getLongValue());
            }
            else if (Objects.equals(item.getMetric(), MetricEnum.MY_STAR_COUNT.getValue())){
                itemStatistic.setMyStarCount(item.getLongValue());
            }
            result.putIfAbsent(itemStatistic.getItemId(), itemStatistic);
        });
        return result;
    }
}
